
#include "bsp.h"

typedef struct
{
    uint32_t uart_port;   /* UART端口 */

    uart_fifo_send_cb_t send_befor_cb;  /* 发送之前执行的 */
    uart_fifo_send_cb_t send_ing_cb;    /* 每个字节发送时执行的 */
    uart_fifo_send_cb_t send_over_cb;   /* 一帧数据发送完成后执行的 */

    uart_fifo_recv_cb_t recv_idle_cb;  /* 串口空闲（不再接收数据）时执行的 */
    uart_fifo_recv_cb_t recv_ing_cb;   /* 串口每接收一个字节数据时执行的 */

    queue_t send_queue;  /* 发送环形队列 */
    queue_t recv_queue;  /* 接收环形队列 */
}uart_fifo_t;

#if USE_UART0_FIFO
static uart_fifo_t _uart0;
static uint8_t _uart0_send_buff[UART0_SEND_BUFF_SIZE];
static uint8_t _uart0_recv_buff[UART0_RECV_BUFF_SIZE];
#endif

#if USE_UART5_FIFO
static uart_fifo_t _uart5;
static uint8_t _uart5_send_buff[UART5_SEND_BUFF_SIZE];
static uint8_t _uart5_recv_buff[UART5_RECV_BUFF_SIZE];
#endif

#if USE_UART0_FIFO  || USE_UART1_FIFO  || USE_UART2_FIFO  || USE_UART3_FIFO  || \
    USE_UART4_FIFO  || USE_UART5_FIFO  || USE_UART6_FIFO  || USE_UART7_FIFO
/***************************************************************************************************
 * @fn      init_uart_fifo_struct
 *
 * @brief   初始化串口相关变量
 *
 * @param  com 串口端口号
 * @param  uart_port 串口硬件编号USARTx或者UARTx
 *
 * @return  无 
 */
static void init_uart_fifo_struct(uart_fifo_t *uart, uint32_t uart_port)
{
    /* UART端口 */
    uart->uart_port = uart_port;   

    /* 发送回调函数，先清空 */
    uart->send_befor_cb = NULL;
    uart->send_ing_cb   = NULL;
    uart->send_over_cb  = NULL;

    /* 接收回调函数，先清空 */
    uart->recv_idle_cb = NULL;
    uart->recv_ing_cb  = NULL;
}
#endif

/***************************************************************************************************
 * @fn      get_uart_fifo_struct
 *
 * @brief   获取串口相关的信息
 *
 * @param  com 串口端口号
 *
 * @return  串口相关的信息 
 */
static uart_fifo_t *get_uart_fifo_struct(uart_fifo_com_e com)
{
    uart_fifo_t *uart = NULL;

    switch (com)
    {
        case UART_FIFO_COM0:
        {
        #if USE_UART0_FIFO
            uart = &_uart0;
        #endif
            break;
        }
        
        case UART_FIFO_COM1:
        {
            break;
        }
        
        case UART_FIFO_COM2:
        {
            break;
        }
        
        case UART_FIFO_COM3:
        {
            break;
        }
        
        case UART_FIFO_COM4:
        {
            break;
        }
        
        case UART_FIFO_COM5:
        {
        #if USE_UART5_FIFO
            uart = &_uart5;
        #endif
            break;
        }
        
        case UART_FIFO_COM6:
        {
            break;
        }
        
        case UART_FIFO_COM7:
        {
            break;
        }

        default:
        {
            break;
        }
    }

    return uart;
}

#if USE_UART0_FIFO
/***************************************************************************************************
 * @fn      uart0_init_var
 *
 * @brief   初始化串口0相关变量
 *
 * @param  无
 *
 * @return  无 
 */
static void uart0_init_var(void)
{
    init_uart_fifo_struct(&_uart0, USART0);

    queue_init(&_uart0.send_queue, _uart0_send_buff, UART0_SEND_BUFF_SIZE);
    queue_init(&_uart0.recv_queue, _uart0_recv_buff, UART0_RECV_BUFF_SIZE);
}

/***************************************************************************************************
 * @fn      uart0_init_hward
 *
 * @brief   初始化串口0相关硬件
 *
 * @param  无
 *
 * @return  无 
 */
static void uart0_init_hward(uint32_t baudval)
{
    /* 串口1 TX = PA9   RX = PA10 或 TX = PB6   RX = PB7*/
    rcu_periph_clock_enable(RCU_GPIOA);  /* 使能GPIO时钟 */
    rcu_periph_clock_enable(RCU_USART0); /* 使能串口时钟 */

    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9);
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_10);
    
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);

    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
    
    /* 配置USART的参数 */
    usart_deinit(USART0);  /* RCU配置恢复默认值 */
    usart_baudrate_set(USART0, baudval);  /* 设置波特率 */
    usart_stop_bit_set(USART0, USART_STB_1BIT);  /* 设置停止位 */
    usart_word_length_set(USART0, USART_WL_8BIT);  /* 设置数据字长度 */
    usart_parity_config(USART0, USART_PM_NONE);  /* 设置奇偶校验位 */
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);  /* 使能接收 */
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);  /* 使能发送 */

    usart_interrupt_enable(USART0, USART_INT_RBNE);  /* 使能接收缓冲区非空中断 */

    nvic_irq_enable(USART0_IRQn, 1, 0);  /* 使能串口中断，设置优先级 */

    usart_enable(USART0);  /* 使能串口 */
}
#endif

#if USE_UART5_FIFO
/***************************************************************************************************
 * @fn      uart5_init_var
 *
 * @brief   初始化串口5相关变量
 *
 * @param  无
 *
 * @return  无 
 */
static void uart5_init_var(void)
{
    init_uart_fifo_struct(&_uart5, USART5);

    queue_init(&_uart5.send_queue, _uart5_send_buff, UART5_SEND_BUFF_SIZE);
    queue_init(&_uart5.recv_queue, _uart5_recv_buff, UART5_RECV_BUFF_SIZE);
}

/***************************************************************************************************
 * @fn      uart5_init_hward
 *
 * @brief   初始化串口5相关硬件
 *
 * @param  无
 *
 * @return  无 
 */
static void uart5_init_hward(uint32_t baudval)
{
    /* 串口5 TX = PA11   RX = PA12 */
    rcu_periph_clock_enable(RCU_GPIOA);  /* 使能GPIO时钟 */
    rcu_periph_clock_enable(RCU_USART5); /* 使能串口时钟 */

    gpio_af_set(GPIOA, GPIO_AF_8, GPIO_PIN_11);
    gpio_af_set(GPIOA, GPIO_AF_8, GPIO_PIN_12);
    
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_11);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_11);

    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_12);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12);
    
    /* 配置USART的参数 */
    usart_deinit(USART5);  /* RCU配置恢复默认值 */
    usart_baudrate_set(USART5, baudval);  /* 设置波特率 */
    usart_stop_bit_set(USART5, USART_STB_1BIT);  /* 设置停止位 */
    usart_word_length_set(USART5, USART_WL_8BIT);  /* 设置数据字长度 */
    usart_parity_config(USART5, USART_PM_NONE);  /* 设置奇偶校验位 */
    usart_receive_config(USART5, USART_RECEIVE_ENABLE);  /* 使能接收 */
    usart_transmit_config(USART5, USART_TRANSMIT_ENABLE);  /* 使能发送 */

    usart_interrupt_enable(USART5, USART_INT_RBNE);  /* 使能接收缓冲区非空中断 */
    usart_interrupt_enable(USART5, USART_INT_IDLE);  /* 使能空闲中断 */

    nvic_irq_enable(USART5_IRQn, 1, 0);  /* 使能串口中断，设置优先级 */

    usart_enable(USART5);  /* 使能串口 */
}
#endif

/***************************************************************************************************
 * @fn      uart_fifo_init
 *
 * @brief   初始化串口硬件以及一些相关数据
 *
 * @param  com 串口端口号
 * @param  send_befor 发送数据前执行的回调函数
 * @param  send_ing 每发送一个字节执行的回调函数
 * @param  send_over 一帧数据发送完成后执行的回调函数
 *
 * @return  注册成功返回TRUE，否则返回FALSE 
 */
BOOL uart_fifo_init(uart_fifo_com_e com, uint32_t baudval)
{
    BOOL ret = FALSE;

    if (UART_FIFO_COM0 == com)
    {
    #if USE_UART0_FIFO
        uart0_init_var();
        uart0_init_hward(baudval);
        ret = TRUE;
    #endif
    }
    else if (UART_FIFO_COM5 == com)
    {
    #if USE_UART5_FIFO
        uart5_init_var();
        uart5_init_hward(baudval);
        ret = TRUE;
    #endif
    }

    return ret;
}

/***************************************************************************************************
 * @fn      uart_fifo_set_baud
 *
 * @brief   设置串口波特率
 *
 * @param  com 串口端口号
 * @param  baudval 波特率的值
 *
 * @return  注册成功返回TRUE，否则返回FALSE 
 */
BOOL uart_fifo_set_baud(uart_fifo_com_e com, uint32_t baudval)
{
    BOOL ret = FALSE;

    /* 获取串口fifo相关信息 */
    uart_fifo_t *uart = get_uart_fifo_struct(com);

    if (NULL != uart)
    {
        usart_baudrate_set(uart->uart_port, baudval);

        ret = TRUE;
    }

    return ret;
}

/***************************************************************************************************
 * @fn      uart_fifo_reg_send_cb
 *
 * @brief   注册发送回调函数
 *
 * @param  com 串口端口号
 * @param  send_befor 发送数据前执行的回调函数
 * @param  send_ing 每发送一个字节执行的回调函数
 * @param  send_over 一帧数据发送完成后执行的回调函数
 *
 * @return  注册成功返回TRUE，否则返回FALSE 
 */
BOOL uart_fifo_reg_send_cb(uart_fifo_com_e com, 
                           uart_fifo_send_cb_t send_befor,
                           uart_fifo_send_cb_t send_ing,
                           uart_fifo_send_cb_t send_over)
{
    /* 获取串口fifo相关信息 */
    uart_fifo_t *uart = get_uart_fifo_struct(com);

    if (NULL != uart)
    {
        /* 注册回调函数 */
        uart->send_befor_cb = send_befor;
        uart->send_ing_cb   = send_ing;
        uart->send_over_cb  = send_over;

        return TRUE;
    }
    else
    {
        return FALSE;
    }
}                           

/***************************************************************************************************
 * @fn      uart_fifo_reg_recv_cb
 *
 * @brief   注册串口接收回调函数
 *
 * @param  com 串口端口号
 * @param  recv_idle 串口空闲回调函数
 * @param  recv_ing 串口每接收一个字节执行的回调函数
 *
 * @return  注册成功返回TRUE，否则返回FALSE 
 */
BOOL uart_fifo_reg_recv_cb(uart_fifo_com_e com, 
                           uart_fifo_recv_cb_t recv_idle,
                           uart_fifo_recv_cb_t recv_ing)
{
    /* 获取串口fifo相关信息 */
    uart_fifo_t *uart = get_uart_fifo_struct(com);

    if (NULL != uart)
    {
        /* 注册回调函数 */
        uart->recv_idle_cb = recv_idle;
        uart->recv_ing_cb  = recv_ing;

        return TRUE;
    }
    else
    {
        return FALSE;
    }
}                           

/***************************************************************************************************
 * @fn      uart_fifo_send
 *
 * @brief   发送数据
 *
 * @param  com 串口端口号
 * @param  buff 要发送的数据
 * @param  len 发送的数据长度（单位：字节）
 *
 * @return  成功发送的数据长度（单位：字节）
 */
int32_t uart_fifo_send(uart_fifo_com_e com, uint8_t *buff, int32_t len)
{
    int32_t length = 0;
    uart_fifo_t *uart = get_uart_fifo_struct(com);  /* 获取串口fifo相关信息 */

    if (NULL == uart)
    {
        return length;
    }
    /* 发送前要执行的函数 */
    if (uart->send_befor_cb)
    {
        uart->send_befor_cb(NULL);
    }
    
    /* 把数据暂存到发送缓冲 */
    length = queue_enter_buffer(&uart->send_queue, buff, len);

    /* 使能发送缓冲区空中断 */
    usart_interrupt_enable(uart->uart_port, USART_INT_TBE);

    return length;
}

/***************************************************************************************************
 * @fn      uart_fifo_recv
 *
 * @brief   从接收缓冲中，获取数据
 *
 * @param  com 串口端口号
 * @param  buff 要发送的数据
 * @param  len 想要获取的数据长度（单位：字节）
 *
 * @return  成功获取到的数据长度（单位：字节）
 */
int32_t uart_fifo_recv(uart_fifo_com_e com, uint8_t *buff, int32_t len)
{
    uart_fifo_t *uart = get_uart_fifo_struct(com);

    return queue_delete_buffer(&uart->recv_queue, buff, len);
}

/***************************************************************************************************
 * @fn      uart_fifo_clear_recv
 *
 * @brief   清除已经接收到的数据
 *
 * @param  com 串口端口号
 *
 * @return  清除成功返回TRUE，否则返回FALSE
 */
BOOL uart_fifo_clear_recv(uart_fifo_com_e com)
{
    uart_fifo_t *uart = get_uart_fifo_struct(com);

    return queue_clear(&uart->recv_queue);
}

/***************************************************************************************************
 * @fn      uart_fifo_clear_send
 *
 * @brief   清除已经填充的数据
 *
 * @param  com 串口端口号
 *
 * @return  清除成功返回TRUE，否则返回FALSE
 */
BOOL uart_fifo_clear_send(uart_fifo_com_e com)
{
    uart_fifo_t *uart = get_uart_fifo_struct(com);

    return queue_clear(&uart->send_queue);
}

/***************************************************************************************************
 * @fn      uart_fifo_get_recv_len
 *
 * @brief   获取已经收到的数据个数（单位：字节）
 *
 * @param  com 串口端口号
 *
 * @return  已经收到的数据个数
 */
int32_t uart_fifo_get_recv_len(uart_fifo_com_e com)
{
    uart_fifo_t *uart = get_uart_fifo_struct(com);

    return queue_length(&uart->recv_queue);
}

/***************************************************************************************************
 * @fn      uart_fifo_irq_handler
 *
 * @brief   串口中断处理函数
 *
 * @param  com 串口端口号
 *
 * @return  无
 */
void uart_fifo_irq_handler(uart_fifo_com_e com)
{
    uint8_t data_recv, data_send;
    uart_fifo_t *uart = get_uart_fifo_struct(com);

    if (NULL != uart)
    {
        /* 处理接收中断  */
        if(usart_interrupt_flag_get(uart->uart_port, USART_INT_FLAG_RBNE) != RESET)
        {
            /* 从串口接收数据寄存器读取数据存放到接收FIFO */
            data_recv = usart_data_receive(uart->uart_port);
            queue_enter(&uart->recv_queue, data_recv);
            
            /* 执行正在接收数据回调函数 */
            if (NULL != uart->recv_ing_cb)
            {
                uart->recv_ing_cb(&data_recv);
            }

            /* 清接收中断标志 */
            usart_interrupt_flag_clear(uart->uart_port, USART_INT_FLAG_RBNE);
        }

        /* 发送缓冲区空中断 */
        if(usart_interrupt_flag_get(uart->uart_port, USART_INT_FLAG_TBE) != RESET)
        {
            /* 从缓冲区中获取数据，然后发送 */
            if (queue_delete(&uart->send_queue, &data_send))  /* 能获取到数据 */
            {
                usart_data_transmit(uart->uart_port, data_send);
                
                if (NULL != uart->send_ing_cb)
                {
                    uart->send_ing_cb(&data_send);
                }
            }
            else  /* 没有数据了或者出错（正常不会走到这里） */
            {
                usart_interrupt_disable(uart->uart_port, USART_INT_TBE);
                usart_interrupt_enable(uart->uart_port, USART_INT_TC);
            }

            /* 发送缓冲已经没有数据 */
            if (queue_length(&uart->send_queue) == 0)
            {
                /* 关闭发送缓冲区空中断，开启发送完成中断 */
                usart_interrupt_disable(uart->uart_port, USART_INT_TBE);
                usart_interrupt_enable(uart->uart_port, USART_INT_TC);
            }
            
            /* 清发送缓冲区空中断 */
            usart_interrupt_flag_clear(uart->uart_port, USART_INT_FLAG_TBE);
        }

        /* 发送完成中断 */
        if(usart_interrupt_flag_get(uart->uart_port, USART_INT_FLAG_TC) != RESET)
        {
            /* 执行空闲中断回调函数 */
            if (NULL != uart->send_over_cb)
            {
                uart->send_over_cb(NULL);
            }

            /* 关闭发送完成中断 */
            usart_interrupt_disable(uart->uart_port, USART_INT_TC);

            /* 清发送完成中断 */
            usart_interrupt_flag_clear(uart->uart_port, USART_INT_FLAG_TC);
        }

        /* 空闲中断 */
        if(usart_interrupt_flag_get(uart->uart_port, USART_INT_FLAG_IDLE) != RESET)
        {
            /* 执行空闲中断回调函数 */
            if (NULL != uart->recv_idle_cb)
            {
                uart->recv_idle_cb(NULL);
            }

            /* 清空闲中断 */
            usart_interrupt_flag_clear(uart->uart_port, USART_INT_FLAG_IDLE);
        }

        /* 溢出错误标志为1 */
        if(usart_interrupt_flag_get(uart->uart_port, USART_INT_FLAG_ERR_ORERR) == SET)       
        {                                                         
            usart_interrupt_flag_clear(uart->uart_port, USART_INT_FLAG_ERR_ORERR);  /* 清除溢出错误标志 */
        }
    }
}

#if USE_UART0_FIFO
void USART0_IRQHandler(void)
{
    uart_fifo_irq_handler(UART_FIFO_COM0);
}
#endif

#if USE_UART1_FIFO
void USART1_IRQHandler(void)
{
    uart_fifo_irq_handler(UART_FIFO_COM1);
}
#endif

#if USE_UART2_FIFO
void USART2_IRQHandler(void)
{
    uart_fifo_irq_handler(UART_FIFO_COM2);
}
#endif

#if USE_UART3_FIFO
void UART3_IRQHandler(void)
{
    uart_fifo_irq_handler(UART_FIFO_COM3);
}
#endif

#if USE_UART4_FIFO
void UART4_IRQHandler(void)
{
    uart_fifo_irq_handler(UART_FIFO_COM4);
}
#endif

#if USE_UART5_FIFO
void USART5_IRQHandler(void)
{
    uart_fifo_irq_handler(UART_FIFO_COM5);
}
#endif

#if USE_UART6_FIFO
void UART6_IRQHandler(void)
{
    uart_fifo_irq_handler(UART_FIFO_COM6);
}
#endif

#if USE_UART7_FIFO
void UART7_IRQHandler(void)
{
    uart_fifo_irq_handler(UART_FIFO_COM7);
}
#endif


